home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 March: Reference Library / Dev.CD Mar 96 RL / Dev.CD Mar 96 RL.toast / Technical Documentation / develop / develop Issue 25 / develop Issue 25 code / Flicker Free / flicker free.c next >
Encoding:
C/C++ Source or Header  |  1995-12-15  |  19.1 KB  |  754 lines  |  [TEXT/MPS ]

  1. /*---------------------------------------------------------------------------------
  2.  
  3.     FILE:
  4.         flicker free.c
  5.     
  6.     DESCRIPTION:
  7.         this contains a demonstration of how to use the screen
  8.         buffering library to obtain flicker free drawing.
  9.     
  10.     COPYRIGHT:
  11.         ©1995 Hugo M. Ayala
  12.         ©1995 Apple Computer Inc.
  13.         
  14.     CHANGE LOG:
  15.     
  16.         07/07/95        Hugo        first version.
  17.  
  18. ---------------------------------------------------------------------------------*/
  19. #include <Types.h>
  20. #include <Windows.h>
  21. #include <Dialogs.h>
  22. #include <DiskInit.h>
  23. #include <Desk.h>
  24. #include <Memory.h>
  25. #include <Events.h>
  26. #include <Errors.h>
  27. #include <Fonts.h>
  28. #include <Menus.h>
  29. #include <SegLoad.h>
  30. #include <ToolUtils.h>
  31. #include <Quickdraw.h>
  32. #include <GestaltEqu.h>
  33. #include <Timer.h>
  34.  
  35. #include "GXExceptions.h"
  36.  
  37. #include "math routines.h"
  38. #include "graphics routines.h"
  39. #include "graphics macintosh.h"
  40. #include "graphics toolbox.h"
  41.  
  42. #include "screen buffering.h"
  43.  
  44. #define rAboutAlert                    128
  45. #define rPleaseInstallGX        129
  46. #define rTestResult                    130
  47.  
  48. #define rMenuBar                        128
  49. #define rDocWindow                    128
  50.  
  51. #define    rApple        128
  52. #define rFile            129
  53. #define rDrawing    130
  54.  
  55. #define rAbout                         1
  56. #define rOneParticle            1
  57. #define rTenParticles            2
  58. #define rFiftyParticles        3
  59.  
  60. #define rFullWindowBuffering    5
  61. #define rNoWindowBuffering        6
  62. #define rHalfAndHalf                    7
  63.  
  64. #define rRefresRateTest                9
  65.  
  66. /*---------------------------------------------------------------------------------
  67.     Some Prototypes.
  68. ---------------------------------------------------------------------------------*/
  69. static void Initialize( void );
  70. static void EventLoop( void );
  71. /*---------------------------------------------------------------------------------
  72.     The application Globals.
  73. ---------------------------------------------------------------------------------*/
  74. struct ApplicationGlobals        {
  75.     
  76.     short        bufferingmethod;
  77.  
  78.     long        sleeptime;
  79.  
  80.     WindowPtr        window;
  81.     gxViewPort    parent;
  82.     gxViewPort    view;
  83.     
  84.     viewPortBuffer        buffer;
  85.     
  86.     gxShape        scene;
  87.     gxShape        erase;
  88.  
  89.     Handle        shapeList;
  90.     Handle        speedList;
  91.     
  92. };
  93.  
  94. struct ApplicationGlobals global;
  95. /*---------------------------------------------------------------------------------
  96.     main
  97. ---------------------------------------------------------------------------------*/
  98. void main()
  99. {
  100.     long version;
  101.  
  102.     InitGraf((Ptr) &qd.thePort );
  103.     InitFonts();
  104.     InitWindows();
  105.     InitMenus();
  106.     InitDialogs( 0L );
  107.     InitCursor();
  108.  
  109.     if( Gestalt( gestaltGraphicsVersion, &version ) == noErr )
  110.         {
  111.             Initialize();
  112.             EventLoop();
  113.         }
  114.     else
  115.         {
  116.             (void) Alert( rPleaseInstallGX, nil );
  117.         }
  118. }
  119. /*---------------------------------------------------------------------------------
  120.     HandleIdle
  121. ---------------------------------------------------------------------------------*/
  122. static void HandleIdle( void )
  123. {
  124.     long count;
  125.     
  126.     if( count = GetHandleSize( global.speedList ) / sizeof( gxPoint ) )
  127.         {
  128.             long indx;
  129.             
  130.             gxRectangle    bounds;
  131.             
  132.             gxShape        *shapePtr;
  133.             gxPoint        *speedPtr;
  134.             
  135.             bounds.left = bounds.top = 0;
  136.             bounds.right = ff( global.window->portRect.right );
  137.             bounds.bottom = ff( global.window->portRect.bottom );
  138.             
  139.             HLock( global.shapeList ); shapePtr = * (gxShape **) global.shapeList;
  140.             HLock( global.speedList ); speedPtr = * (gxPoint **) global.speedList;
  141.             
  142.             for( indx = 0; indx < count; indx += 1 )
  143.                 {
  144.                     Fixed            radius;        
  145.                     gxPoint        location;
  146.                     
  147.                     gxRectangle        bbox;
  148.                     
  149.                     GXGetShapeBounds( shapePtr[ indx ], 0, &bbox );
  150.                     
  151.                     radius = ( bbox.right - bbox.left ) / 2;
  152.                     
  153.                     location.x = bbox.left + radius;
  154.                     location.y = bbox.top + radius;
  155.                     
  156.                     location.x += speedPtr[ indx ].x;
  157.                     location.y += speedPtr[ indx ].y;
  158.                     
  159.                     if( ( location.x - radius ) < bounds.left && speedPtr[ indx ].x < 0 )
  160.                         {
  161.                             speedPtr[ indx ].x = -speedPtr[ indx ].x;
  162.                         }
  163.                     
  164.                     if( bounds.right < ( location.x + radius ) && speedPtr[ indx ].x > 0 )
  165.                         {
  166.                             speedPtr[ indx ].x = -speedPtr[ indx ].x;
  167.                         }
  168.  
  169.                     check( bounds.left <= location.x && location.x <= bounds.right );
  170.                     
  171.                     if( ( location.y - radius ) < bounds.top && speedPtr[ indx ].y < 0 )
  172.                         {
  173.                             speedPtr[ indx ].y = -speedPtr[ indx ].y;
  174.                         }
  175.                     
  176.                     if( bounds.bottom < ( location.y + radius ) && speedPtr[ indx ].y > 0 )
  177.                         {
  178.                             speedPtr[ indx ].y = -speedPtr[ indx ].y;
  179.                         }
  180.  
  181.                     check( bounds.top <= location.y && location.y <= bounds.bottom );
  182.                     
  183.                     GXMoveShapeTo( shapePtr[ indx ], location.x - radius, location.y - radius );
  184.                 }
  185.  
  186.             HUnlock( global.speedList );
  187.             HUnlock( global.shapeList );
  188.  
  189.             /* this draws the unbuffered half */
  190.             
  191.             GXDrawShape( global.erase );
  192.             GXDrawShape( global.scene );
  193.  
  194.             /* and this draws the buffered half */
  195.             
  196.             DrawShapeBuffered( global.buffer, global.scene, nil );
  197.         }
  198. }
  199. /*---------------------------------------------------------------------------------
  200.     PickFixed 
  201. ---------------------------------------------------------------------------------*/
  202. static Fixed PickFixed( const Fixed low, const Fixed high )
  203. {
  204.     Fixed    range = high - low;
  205.     short    start = Random();
  206.     
  207.     if( start < 0 ) start = -start;
  208.     
  209.     return FixedMultiply( FixRatio( start, 0x7FFF ), range ) + low;
  210. }
  211. /*---------------------------------------------------------------------------------
  212.     NewParticleShape 
  213. ---------------------------------------------------------------------------------*/
  214. static gxShape NewParticleShape( const Fixed radius )
  215. {
  216.     #define     particlepoints        5
  217.     
  218.     gxPolar    round;
  219.     long        indx;
  220.     
  221.     struct        {
  222.         long    contours;
  223.         long    vectors;
  224.         long    control;
  225.         
  226.         gxPoint    points[ particlepoints ];
  227.     } path;
  228.     
  229.     path.contours = 1;
  230.     path.vectors = particlepoints;
  231.     path.control = 0xFFFFFFFF;
  232.     
  233.     round.radius = radius;
  234.     round.angle = 0;
  235.     
  236.     for( indx = 0; indx < particlepoints; indx += 1 )
  237.         {
  238.             PolarToPoint( &round, & path.points[ indx ] );
  239.             round.angle += ff( 360 ) / particlepoints;
  240.         }
  241.  
  242.     #undef particlepoints
  243.     
  244.     return GXNewPaths((gxPaths *) &path );
  245. }
  246. /*---------------------------------------------------------------------------------
  247.     SetShapeRandomColor 
  248. ---------------------------------------------------------------------------------*/
  249. static void SetShapeRandomColor( gxShape sh  )
  250. {
  251.     gxColor    color;
  252.     
  253.     color.space = gxHSVSpace;
  254.     color.profile = nil;
  255.     color.element.hsv.hue = (gxColorValue) Random();
  256.     color.element.hsv.saturation = 0xFFFF;
  257.     color.element.hsv.value = 0xFFFF;
  258.     
  259.     GXSetShapeColor( sh, &color );
  260. }
  261. /*---------------------------------------------------------------------------------
  262.     SetWindowBuffering
  263. ---------------------------------------------------------------------------------*/
  264. static void SetWindowBuffering( const short which )
  265. {
  266.     gxShape        bufferclip;
  267.     gxShape        windowclip;
  268.     
  269.     gxRectangle    bufferbox;
  270.     gxRectangle    windowbox;
  271.     
  272.     Rect    bounds = global.window->portRect;
  273.         
  274.     switch( which )
  275.         {
  276.             case rFullWindowBuffering:
  277.                 bufferbox.left = ff( bounds.left );
  278.                 bufferbox.top = ff( bounds.top );
  279.                 bufferbox.right = ff( bounds.right );
  280.                 bufferbox.bottom = ff( bounds.bottom );
  281.                 windowbox.left =
  282.                 windowbox.top =
  283.                 windowbox.right = 
  284.                 windowbox.bottom = 0;
  285.                 break;
  286.             case rNoWindowBuffering:
  287.                 bufferbox.left =
  288.                 bufferbox.top =
  289.                 bufferbox.right = 
  290.                 bufferbox.bottom = 0;
  291.                 windowbox.left = ff( bounds.left );
  292.                 windowbox.top = ff( bounds.top );
  293.                 windowbox.right = ff( bounds.right );
  294.                 windowbox.bottom = ff( bounds.bottom );
  295.                 break;
  296.  
  297.             default:
  298.             case rHalfAndHalf:
  299.                 bufferbox.left = ff( bounds.left );
  300.                 bufferbox.top = ff( bounds.top );
  301.                 bufferbox.right = ff( ( bounds.right + bounds.left ) / 2 );
  302.                 bufferbox.bottom = ff( bounds.bottom );
  303.                 windowbox.left = bufferbox.right;
  304.                 windowbox.top = bufferbox.top;
  305.                 windowbox.right = ff( bounds.right );
  306.                 windowbox.bottom = bufferbox.bottom;
  307.                 break;
  308.         }
  309.     
  310.     bufferclip = GXNewRectangle( &bufferbox );
  311.     windowclip = GXNewRectangle( &windowbox );
  312.     
  313.     GXSetViewPortClip( global.view, windowclip );
  314.     UpdateViewPortWBuffer( global.buffer, bufferclip, nil );
  315.     
  316.     GXDisposeShape( windowclip );
  317.     GXDisposeShape( bufferclip );
  318.     
  319.     global.bufferingmethod = which;
  320. }
  321. /*---------------------------------------------------------------------------------
  322.     SetSceneParticleCount
  323. ---------------------------------------------------------------------------------*/
  324. static void SetSceneParticleCount( const long newcount )
  325. {
  326.     gxShape    *shapePtr;
  327.     gxPoint    *speedPtr;
  328.     
  329.     long indx;
  330.  
  331.     /* delete all of the shapes currently in the scene */
  332.     /* this makes room for the new shape that we're going to make */
  333.     
  334.     GXSetPictureParts( global.scene, 1, gxSelectToEnd, 0, nil, nil, nil, nil );
  335.     
  336.     SetHandleSize( global.shapeList, newcount * sizeof( gxShape ) );
  337.     nrequire( MemError(), ResizeShapeListFailed );
  338.     
  339.     SetHandleSize( global.speedList, newcount * sizeof( gxPoint ) );
  340.     nrequire( MemError(), ResizeSpeedListFailed );
  341.     
  342.     HLock( global.shapeList ); shapePtr = * (gxShape **) global.shapeList;
  343.     HLock( global.speedList ); speedPtr = * (gxPoint **) global.speedList;
  344.     
  345.     for( indx = 0; indx < newcount; indx += 1 )
  346.         {
  347.             Fixed        radius;
  348.             gxPolar    velocity;
  349.             
  350.             gxRectangle        bounds;
  351.             
  352.             gxShape        particle;
  353.             
  354.             bounds.left = bounds.top = 0;
  355.             bounds.right = ff( global.window->portRect.right );
  356.             bounds.bottom = ff( global.window->portRect.bottom );
  357.             
  358.             #define minimumParticleRadius        ff(  5 )
  359.             #define maximumParticleRadius        ff( 20 )
  360.             
  361.             radius = PickFixed( minimumParticleRadius, maximumParticleRadius );
  362.             
  363.             particle = NewParticleShape( radius );
  364.  
  365.             GXMoveShapeTo( particle,    PickFixed( bounds.left, bounds.right ),
  366.                                                                 PickFixed( bounds.top, bounds.bottom ) );
  367.             SetShapeRandomColor( particle );
  368.             
  369.             shapePtr[ indx ] = particle;
  370.  
  371.             velocity.radius = maximumParticleRadius - radius + fixed1/2;
  372.             velocity.angle = PickFixed( ff( 0 ), ff( 360 ) );
  373.             
  374.             PolarToPoint( &velocity, &speedPtr[ indx ] );
  375.             
  376.             #undef minimumParticleRadius
  377.             #undef maximumParticleRadius
  378.         }
  379.     
  380.     GXSetPictureParts( global.scene, 1, gxSelectToEnd, newcount, 
  381.             shapePtr, nil, nil, nil );
  382.         
  383.     for( indx = 0; indx < newcount; indx += 1 )
  384.         GXDisposeShape( shapePtr[ indx ] );
  385.     
  386.     HUnlock( global.speedList );
  387.     HUnlock( global.shapeList );
  388.             
  389. ResizeShapeListFailed: ResizeSpeedListFailed:;
  390. }
  391. /*---------------------------------------------------------------------------------
  392.     ReportTestResult
  393. ---------------------------------------------------------------------------------*/
  394. static void ReportTestResult( const long count, const long time )
  395. {
  396.     Str255    countstring;
  397.     Str255    timestring;
  398.     
  399.     NumToString( count, countstring );
  400.     NumToString( time, timestring );
  401.     
  402.     ParamText( countstring, timestring, nil, nil );
  403.     (void) Alert( rTestResult, nil );
  404. }
  405. /*---------------------------------------------------------------------------------
  406.     RefreshRateTest
  407. ---------------------------------------------------------------------------------*/
  408. static void RefreshRateTest( void )
  409. {
  410.     gxRectangle        bounds;
  411.     gxShape        sh;
  412.     
  413.     Point    size;
  414.         
  415.     long count;
  416.     long ticks;
  417.     
  418.     #define        durationInTicks        (5*60)
  419.     
  420.     size.h = ( global.window->portRect.right - global.window->portRect.left ) >> 2;
  421.     size.v = ( global.window->portRect.bottom - global.window->portRect.top ) >> 2;
  422.     
  423.     bounds.left = ff( size.h );
  424.     bounds.top = ff( size.v );
  425.     bounds.right = ff( size.h * 3 );
  426.     bounds.bottom = ff( size.v * 3 );
  427.     
  428.     sh = GXNewRectangle( &bounds );
  429.     SetShapeRandomColor( sh );
  430.     
  431.     GXSetShapeViewPorts( sh, 1, & global.view );
  432.     
  433.     count = 0;
  434.     ticks =  TickCount() + durationInTicks;
  435.     
  436.     do
  437.         {
  438.             GXDrawShape( global.erase );
  439.             GXDrawShape( sh );
  440.             
  441.             DrawShapeBuffered( global.buffer, sh, nil );
  442.             
  443.             count += 1;
  444.             
  445.         } while( TickCount() < ticks );
  446.         
  447.     ReportTestResult( count, durationInTicks / 60 );
  448.  
  449.     #undef durationInTicks
  450.     
  451.     GXDisposeShape( sh );
  452. }
  453. /*---------------------------------------------------------------------------------
  454.     HandleDrawingMenu
  455. ---------------------------------------------------------------------------------*/
  456. static void HandleDrawingMenu( const short menuitem )
  457. {
  458.     MenuHandle        menuHdl = GetMenuHandle( rDrawing );
  459.     
  460.     switch( menuitem )
  461.         {
  462.             case rOneParticle:
  463.                 CheckItem( menuHdl, rOneParticle, true );
  464.                 CheckItem( menuHdl, rTenParticles, false );
  465.                 CheckItem( menuHdl, rFiftyParticles, false );
  466.                 SetSceneParticleCount( 1 );
  467.                 break;
  468.             case rTenParticles:
  469.                 CheckItem( menuHdl, rOneParticle, false );
  470.                 CheckItem( menuHdl, rTenParticles, true );
  471.                 CheckItem( menuHdl, rFiftyParticles, false );
  472.                 SetSceneParticleCount( 10 );
  473.                 break;
  474.             case rFiftyParticles:
  475.                 CheckItem( menuHdl, rOneParticle, false );
  476.                 CheckItem( menuHdl, rTenParticles, false );
  477.                 CheckItem( menuHdl, rFiftyParticles, true );
  478.                 SetSceneParticleCount( 50 );
  479.                 break;
  480.  
  481.             /* ----------------------- */
  482.  
  483.             case rFullWindowBuffering:
  484.                 CheckItem( menuHdl, rFullWindowBuffering, true );
  485.                 CheckItem( menuHdl, rNoWindowBuffering, false );
  486.                 CheckItem( menuHdl, rHalfAndHalf, false );
  487.                 SetWindowBuffering( rFullWindowBuffering );
  488.                 break;
  489.             case rNoWindowBuffering:
  490.                 CheckItem( menuHdl, rFullWindowBuffering, false );
  491.                 CheckItem( menuHdl, rNoWindowBuffering, true );
  492.                 CheckItem( menuHdl, rHalfAndHalf, false );
  493.                 SetWindowBuffering( rNoWindowBuffering );
  494.                 break;
  495.             case rHalfAndHalf:
  496.                 CheckItem( menuHdl, rFullWindowBuffering, false );
  497.                 CheckItem( menuHdl, rNoWindowBuffering, false );
  498.                 CheckItem( menuHdl, rHalfAndHalf, true );
  499.                 SetWindowBuffering( rHalfAndHalf );
  500.                 break;
  501.  
  502.             /* ----------------------- */
  503.             
  504.             case rRefresRateTest:
  505.                 RefreshRateTest();
  506.                 break;
  507.         }
  508. }
  509. /*---------------------------------------------------------------------------------
  510.     HandleMenuCommand
  511. ---------------------------------------------------------------------------------*/
  512. static void HandleMenuCommand( const long command )
  513. {
  514.  
  515.     short        menuid;
  516.     short        menuitem;
  517.         
  518.     menuid = HiWord( command );
  519.     menuitem = LoWord( command );
  520.     
  521.     switch( menuid )
  522.         {
  523.             case rApple:
  524.                 switch( menuitem )
  525.                     {
  526.                         case rAbout:
  527.                             (void) Alert( rAboutAlert, nil );
  528.                             break;
  529.                         
  530.                         default:
  531.                             {
  532.                                 Str255        daname;
  533.                                 short            darefnum;
  534.                                 
  535.                                 GetMenuItemText( GetMenuHandle( rApple ), menuitem, daname );
  536.                                 darefnum = OpenDeskAcc( daname );
  537.                             }
  538.                             break;
  539.                     }
  540.                 break;
  541.             
  542.             case rFile:
  543.                 ExitToShell();
  544.                 break;
  545.  
  546.             case rDrawing:
  547.                 HandleDrawingMenu( menuitem );
  548.                 break;
  549.         }
  550.  
  551.     HiliteMenu( 0 ); // unselect the menu that was selected
  552.     
  553. }
  554. /*---------------------------------------------------------------------------------
  555.     HandleMouseDown
  556. ---------------------------------------------------------------------------------*/
  557. static void HandleGrowWindow( WindowPtr window, EventRecord *event )
  558. {
  559.     long    growresult;
  560.  
  561.     Rect    param;
  562.     
  563.     param = qd.screenBits.bounds;
  564.     param.left = 40;
  565.     param.top = 40;
  566.     
  567.     if( growresult = GrowWindow( window, event->where, ¶m ) )
  568.         {
  569.             SizeWindow( window, LoWord( growresult ), HiWord( growresult ), true );
  570.         }
  571. }
  572. /*---------------------------------------------------------------------------------
  573.     HandleMouseDown
  574. ---------------------------------------------------------------------------------*/
  575. static void HandleMouseDown( EventRecord *eventPtr )
  576. {
  577.     short                part;
  578.     WindowPtr        window;
  579.     
  580.     part = FindWindow( eventPtr->where, &window );
  581.     
  582.     switch( part )
  583.         {
  584.             case inMenuBar:
  585.                 HandleMenuCommand( MenuSelect( eventPtr->where ) );
  586.                 break;
  587.             
  588.             case inSysWindow:
  589.                 SystemClick( eventPtr, window );
  590.                 break;
  591.  
  592.             case inContent:
  593.                 break;
  594.             
  595.             case inDrag:
  596.                 DragWindow( window, eventPtr->where, &qd.screenBits.bounds );
  597.                 break;
  598.             
  599.             case inGoAway:
  600.                 if( TrackGoAway( window, eventPtr->where ) )
  601.                     ExitToShell();
  602.                 break;
  603.  
  604.             case inGrow:
  605.                 HandleGrowWindow( window, eventPtr );
  606.                 SetWindowBuffering( global.bufferingmethod );
  607.                 break;
  608.             
  609.             case inZoomIn:
  610.             case inZoomOut:
  611.                 if( TrackBox( window, eventPtr->where, part ) )
  612.                     {
  613.                         SetPort( window );
  614.                         ZoomWindow( window, part, false );
  615.                         SetWindowBuffering( global.bufferingmethod );
  616.                     }
  617.                 break;
  618.         }
  619. }
  620. /*---------------------------------------------------------------------------------
  621.     HandleEvent
  622. ---------------------------------------------------------------------------------*/
  623. static void HandleEvent( EventRecord *eventPtr )
  624. {
  625.     
  626.     switch( eventPtr->what )
  627.         {
  628.             case mouseDown:
  629.                 HandleMouseDown( eventPtr );
  630.                 break;
  631.             
  632.             case keyDown:
  633.                 if( ( eventPtr->modifiers & cmdKey ) &&                // check for a menu command key equivalent
  634.                         ( ' ' <= ( eventPtr->message & charCodeMask ) ) ) // but don't filter cmd-arrow keys
  635.                     {
  636.                         HandleMenuCommand( MenuKey( eventPtr->message & charCodeMask ) );
  637.                     }
  638.                 break;
  639.             
  640.             case diskEvt:
  641.                 if( ( eventPtr->message >> 16 ) != noErr )
  642.                     {
  643.                         Point        where = { 100, 100 };
  644.                         
  645.                         DIBadMount( where, eventPtr->message );
  646.                     }
  647.                 break;
  648.             
  649.             case updateEvt:
  650.                 if((WindowPtr) eventPtr->message == global.window )
  651.                     {
  652.                         SetPort( global.window );
  653.  
  654.                         BeginUpdate( global.window );
  655.                         /* we want to draw the whole window, not just the update rgn */
  656.                         EndUpdate( global.window );
  657.  
  658.                         HandleIdle();
  659.                     }
  660.                 break;
  661.                 
  662.             case osEvt:
  663.                 switch( eventPtr->message >> 24 )        // look at the top byte
  664.                     {
  665.                         case suspendResumeMessage:
  666.                             if( eventPtr->message & resumeFlag )
  667.                                 global.sleeptime = 0;
  668.                             else
  669.                                 global.sleeptime = 60;
  670.                             break;
  671.                     }
  672.                 break;
  673.             
  674.             case nullEvent:
  675.             default:
  676.                 HandleIdle();
  677.                 break;
  678.  
  679.         }
  680. }
  681. /*---------------------------------------------------------------------------------
  682.     Initialize
  683. ---------------------------------------------------------------------------------*/
  684. static void Initialize( void )
  685. {
  686.     Handle        menubar;
  687.     gxColor        backcolor;
  688.     
  689.     GXEnterGraphics();
  690.  
  691.     global.sleeptime = 0;
  692.     
  693.     require( menubar = GetNewMBar( rMenuBar ), GetMenuBarFailed );
  694.     SetMenuBar( menubar );
  695.     AppendResMenu( GetMenuHandle( rApple ), 'DRVR' );        // create the apple menu
  696.     DrawMenuBar();
  697.     
  698.     require( global.window = GetNewCWindow( rDocWindow, nil, (WindowPtr) (-1) ), 
  699.         GetWindowFailed );
  700.     
  701.     global.parent = GXNewWindowViewPort( global.window );
  702.     global.view = GXNewViewPort( GXGetViewPortViewGroup( global.parent ) );
  703.     GXSetViewPortParent( global.view, global.parent );
  704.     
  705.     backcolor.space = gxRGBSpace;
  706.     backcolor.profile = nil;
  707.     backcolor.element.rgb.red = 
  708.     backcolor.element.rgb.green = 
  709.     backcolor.element.rgb.blue = 0x0000;
  710.     
  711.     require( global.buffer = NewViewPortWBuffer( global.window, global.view, &backcolor ),
  712.         NewViewPortBufferFailed );
  713.  
  714.     GXSetViewPortDither( global.view, 4 );
  715.     SetViewPortWBufferDither( global.buffer, 4 );
  716.  
  717.     global.scene = GXNewShape( gxPictureType );
  718.     GXSetShapeViewPorts( global.scene, 1, &global.view );
  719.  
  720.     global.erase = GXNewShape( gxFullType );
  721.     GXSetShapeViewPorts( global.erase, 1, &global.view );
  722.     
  723.     require( global.shapeList = NewHandle( 0 ), ShapeListFailed );
  724.     require( global.speedList = NewHandle( 0 ), SpeedListFailed );
  725.     
  726.     HandleDrawingMenu( rFiftyParticles );
  727.     HandleDrawingMenu( rHalfAndHalf );
  728.  
  729.     return;
  730.  
  731. SpeedListFailed: ShapeListFailed: 
  732. NewViewPortBufferFailed: GetWindowFailed: GetMenuBarFailed:    
  733.     ExitToShell();
  734. }
  735. /*---------------------------------------------------------------------------------
  736.     EventLoop
  737. ---------------------------------------------------------------------------------*/
  738. static void EventLoop( void )
  739. {
  740.     EventRecord        event;
  741.     
  742.     for(;;)
  743.         {
  744.             if( WaitNextEvent( everyEvent, &event, global.sleeptime, nil ) )
  745.                 {
  746.                     HandleEvent( &event );
  747.                 }
  748.             else
  749.                 {
  750.                     HandleIdle();
  751.                 }
  752.         }
  753. }
  754.